#pragma once 
#include <iostream>
#include <pthread.h>
#include <queue>

template <class T>
class BlockQueue
{
    static const int defaultnum=5;
public:
    BlockQueue(int maxcapacity=defaultnum)
    :_maxcapacity(maxcapacity)
    {
        pthread_mutex_init(&_mutex,nullptr);
        pthread_cond_init(&c_cond,nullptr);
        pthread_cond_init(&p_cond,nullptr);
    }


    //生产者消费者使用同一把锁，不同条件队列
    void push(const T& in)
    {
        pthread_mutex_lock(&_mutex);

        //不能if判断，if可能会有伪唤醒的情况
        //(当阻塞队列全部唤醒时线程直接执行if之后的语句，条件不满足时也继续执行下去)
        while(_q.size()==_maxcapacity)        
        {
            //资源不就绪则等待且是持有锁的,1.调用时: 自动释放锁，2.若唤醒则重新加锁
            pthread_cond_wait(&p_cond,&_mutex);
        }

        //队列没满，唤醒队列
        _q.push(in);

        //生产者队列一定有数据
        pthread_cond_signal(&c_cond);
        pthread_mutex_unlock(&_mutex);
    }

    //要有返回值
    T pop()
    {
        pthread_mutex_lock(&_mutex);
  
        while(_q.size()==0)
        {
            pthread_cond_wait(&c_cond,&_mutex);     
        }

        T out=_q.front();
        _q.pop();

        pthread_cond_signal(&p_cond);
        pthread_mutex_unlock(&_mutex);
        return out;
    }

    ~BlockQueue()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&c_cond);
        pthread_cond_destroy(&p_cond);
    }

private:
    std::queue<T> _q;               //共享资源
    int _maxcapacity;               //队列的极大值
    pthread_mutex_t _mutex;         //三种关系的互斥关系
    
    //同步关系使用的两条件变量
    pthread_cond_t c_cond;          
    pthread_cond_t p_cond;
};